package com.huangyi.commonmessage.service;

import com.huangyi.commondomain.constants.MessageConstants;
import com.huangyi.commondomain.domain.ResultCode;
import com.huangyi.commondomain.exception.ServiceException;
import com.huangyi.commonredis.service.RedisService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;


import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;

/**
 * 短信验证服务
 */
@Service
public class MessageService {

    /**
     * 存储验证码和过期时间的Map（作为备份存储）
     */
    private static final Map<String, Map<String, Object>> codeStore = new HashMap<>();

    @Autowired
    private RedisService redisService;  // 注入RedisService

    /**
     * 单个手机号，每日发送短信次数的限制
     */
    @Value("${sms.send-limit:}")
    private Integer sendLimit;

    /**
     * 验证码的有效期，单位是分钟
     */
    @Value("${sms.code-expiration:}")
    private Long phoneCodeExpiration;



    /**
     * 绑定用户手机号，生成验证码并设置有效期为五分钟
     * @param phone 用户手机号
     */
    public String sendCode(String phone) {
        // 1 校验是否超过每日的发送限制（针对每个手机号）
        String limitCacheKey = MessageConstants.SMS_CODE_TIMES_KEY + phone;
        Integer times = redisService.getCacheObject(limitCacheKey, Integer.class);
        times = times == null ? 0 : times;
        if (times >= sendLimit) {
            throw new ServiceException(ResultCode.SEND_MSG_FAILED);
        }

        // 2 校验是否在1分钟内频繁发送
        String codeKey = MessageConstants.SMS_CODE_KEY + phone;
        String cacheValue = redisService.getCacheObject(codeKey, String.class);
        long expireTime =  redisService.getExpire(codeKey);
        if (!StringUtils.isEmpty(cacheValue) && expireTime > phoneCodeExpiration * 60 - 60) {
            long time = expireTime - phoneCodeExpiration * 60 + 60;
            throw new ServiceException("操作频繁， 请在"+ time+ "秒之后再试", ResultCode.INVALID_PARA.getCode());
        }

        // 3 生成验证码
        String code = createCode();

        // 4 设置缓存
        redisService.setCacheObject(codeKey, code, phoneCodeExpiration, TimeUnit.MINUTES);
        // 5 设置发送次数（无法预先设置缓存，只能先读后写）
        long seconds = ChronoUnit.SECONDS.between(LocalDateTime.now(),
                LocalDateTime.now().plusDays(1).withHour(0).withMinute(0).withSecond(0).withNano(0));

        redisService.setCacheObject(limitCacheKey, times + 1, seconds, TimeUnit.SECONDS);
        return code;
    }

    /**
     * 从缓存中获取手机号的验证码
     * @param phone 手机号
     * @return 验证码
     */
    public String getCode(String phone) {
        String cacheKey = MessageConstants.SMS_CODE_KEY + phone;
        return redisService.getCacheObject(cacheKey, String.class);
    }

    /**
     * 从缓存中删除手机号的验证码
     * @param phone 手机号
     * @return 验证码
     */
    public boolean deleteCode(String phone) {
        String cacheKey = MessageConstants.SMS_CODE_KEY + phone;
        return redisService.deleteObject(cacheKey);
    }


    /**
     * 校验手机号与验证码是否匹配
     * @param phone 手机号
     * @param code 验证码
     * @return 布尔类型
     */
    public boolean checkCode(String phone, String code) {
        if (getCode(phone) == null || StringUtils.isEmpty(getCode(phone))) {
            throw new ServiceException(ResultCode.INVALID_CODE);
        }
        return getCode(phone).equals(code);
    }
    /**
     * 验证验证码是否有效（检查验证码和有效期）
     * @param key 用户手机号
     * @param inputCode 用户输入的验证码
     * @return 验证码是否有效
     */
    public boolean checkCodeV1(String key, String inputCode) {
        // 1. 先从 Redis 查询
        String redisKey = MessageConstants.SMS_CODE_KEY + key;
        String storedCode = redisService.getCacheObject(redisKey, String.class);
        if (storedCode != null) {
            return storedCode.equals(inputCode);  // 如果在 Redis 找到验证码，则校验
        }

        // 2. 如果 Redis 没有，再从 Map 中查找
        Map<String, Object> codeDetails = codeStore.get(key);
        if (codeDetails == null) {
            return false;
        }

        storedCode = (String) codeDetails.get("code");
        long expiryTime = (long) codeDetails.get("expiry");

        // 3. 验证验证码是否正确，且是否在有效期内
        if (System.currentTimeMillis() > expiryTime) {
            codeStore.remove(key);  // 清除过期的验证码
            return false;
        }

        return storedCode.equals(inputCode);
    }

    /**
     * 生成6位验证码（可以调整为你需要的长度）
     * @return 验证码
     */
    private String createCode() {
        StringBuilder code = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i <= MessageConstants.DEFAULT_SMS_LENGTH; i++) {
            int type = random.nextInt(3);  // 生成0、1、2中的随机数，决定生成字符类型
            switch (type) {
                case 0:
                    code.append(random.nextInt(10));  // 生成数字
                    break;
                case 1:
                    char ch1 = (char) (random.nextInt(26) + 65);  // 生成大写字母
                    code.append(ch1);
                    break;
                case 2:
                    char ch2 = (char) (random.nextInt(26) + 97);  // 生成小写字母
                    code.append(ch2);
                    break;
            }
        }
        return code.toString();
    }
}
